#ifndef SOS_SEMAPHORE_H
#define SOS_SEMAPHORE_H

#include <cmsis_os.h>
#include <core.h>
#include <units.h>

namespace os {
/**
 * @brief 信号类型枚举
 */
enum class SemaphoreType : uint8_t { COUNTING = 0, BINARY, MUTEX };
}  // namespace os

namespace semaphore {
using namespace os;
/**
 * @brief 复用基类（CRTP）
 */
template <typename T>
class SemaphoreBase {
protected:
    QueueHandle_t hSemaphore_ = nullptr;

public:
    SemaphoreBase() = default;

    ~SemaphoreBase() {
        if (hSemaphore_) {
            vSemaphoreDelete(hSemaphore_);
            hSemaphore_ = nullptr;
        }
    }

    SemaphoreBase(SemaphoreBase const&) = delete;
    SemaphoreBase& operator=(SemaphoreBase const&) = delete;

    [[nodiscard]] bool give() const { return xSemaphoreGive(hSemaphore_); }

    [[nodiscard]] bool take(units::time::millisecond_t const waitTime_ms =
                                units::make_unit<units::time::millisecond_t>(portMAX_DELAY)) const {
        return xSemaphoreTake(hSemaphore_, waitTime_ms.to<uint32_t>());
    }

    [[nodiscard]] bool giveFromISR() const {
        static_assert(!T::is_mutex, "Mutex does not support giveFromISR");
        return xSemaphoreGiveFromISR(hSemaphore_, NULL);
    }

    [[nodiscard]] bool takeFromISR() const {
        static_assert(!T::is_mutex, "Mutex does not support takeFromISR");
        return xSemaphoreTakeFromISR(hSemaphore_, NULL);
    }

    [[nodiscard]] bool giveSafe() const {
        static_assert(!T::is_mutex, "Mutex does not support giveSafe");
        if (xPortIsInsideInterrupt()) return xSemaphoreGiveFromISR(hSemaphore_, NULL);
        return xSemaphoreGive(hSemaphore_);
    }

    [[nodiscard]] bool takeSafe() const {
        static_assert(!T::is_mutex, "Mutex does not support TakeSafe");
        if (xPortIsInsideInterrupt()) return xSemaphoreTakeFromISR(hSemaphore_, NULL);
        return xSemaphoreTake(hSemaphore_, portMAX_DELAY);
    }

    [[nodiscard]] QueueHandle_t get_hSemaphore() const { return hSemaphore_; }
};

/**
 * @brief Counting
 */
class CountingSemaphoreImpl : public SemaphoreBase<CountingSemaphoreImpl> {
public:
    static constexpr bool is_mutex = false;

    explicit CountingSemaphoreImpl(uint32_t const maxCount, uint32_t const initialCount = 0) {
        hSemaphore_ = xSemaphoreCreateCounting(maxCount, initialCount);
        os_assert(hSemaphore_ != nullptr, "Counting semaphore creation failed");
    }
};

/**
 * @brief Binary
 */
class BinarySemaphoreImpl : public SemaphoreBase<BinarySemaphoreImpl> {
public:
    static constexpr bool is_mutex = false;

    explicit BinarySemaphoreImpl(uint32_t const initialCount = 0) {
        hSemaphore_ = xSemaphoreCreateBinary();
        os_assert(hSemaphore_ != nullptr, "Binary semaphore creation failed");
        if (initialCount > 0) xSemaphoreGive(hSemaphore_);
    }
};

/**
 * @brief Mutex
 */
class MutexSemaphoreImpl : public SemaphoreBase<MutexSemaphoreImpl> {
public:
    static constexpr bool is_mutex = true;

    explicit MutexSemaphoreImpl() {
        hSemaphore_ = xSemaphoreCreateMutex();
        os_assert(hSemaphore_ != nullptr, "Mutex creation failed");
    }
};

/**
 * @brief 策略选择器
 */
template <SemaphoreType T>
struct SemaphoreStrategy;

template <>
struct SemaphoreStrategy<SemaphoreType::COUNTING> {
    using type = CountingSemaphoreImpl;
};
template <>
struct SemaphoreStrategy<SemaphoreType::BINARY> {
    using type = BinarySemaphoreImpl;
};
template <>
struct SemaphoreStrategy<SemaphoreType::MUTEX> {
    using type = MutexSemaphoreImpl;
};
}  // namespace semaphore

namespace os {
/**
 * @brief 信号量模板类
 */
template <SemaphoreType T>
class Semaphore : public semaphore::SemaphoreStrategy<T>::type {
    using Impl = typename semaphore::SemaphoreStrategy<T>::type;  // ps.这个typename不能删

public:
    using Impl::Impl;  // 继承构造函数
};

/**
 * @brief RAII
 */
template <SemaphoreType T>
class Lock final {
public:
    Semaphore<T>& sem_;
    explicit Lock(Semaphore<T>& sem) : sem_(sem) { sem.take(); }
    ~Lock() { sem_.give(); }
};
}  // namespace os

#endif  // SOS_SEMAPHORE_H
